import React, { type ReactNode, useEffect, useRef, useState } from 'react'
import '@icon-park/react/styles/index.css'
import { downloadFile, formatTime } from 'src/utils'
import { type ReactMusicPlayerProps, type AudioProps, type ControlPanelProps, type PanelModeType, type PlayModeType } from 'src/interface'
import '../index.scss'
import BottomControlPanel from './BottomControlPanel'
import Lyric from './Lyric'
import MiniControlPanel from './MiniControlPanel'
import { ConfigProvider, theme } from 'antd'

let changing = false
let fadeInOutInterval: NodeJS.Timer | number = 0
function ReactMusicPlayer (props: ReactMusicPlayerProps): JSX.Element {
  const {
    token: { colorText }
  } = theme.useToken()
  const audioRef = useRef<HTMLAudioElement>(null)
  const defalutAudio = { author: '', src: '', name: '', pic: '', time: '00:00' }
  const [audioList, setAudioList] = useState(props.audioList)
  const [audio, setAudio] = useState<AudioProps>(defalutAudio)
  const [audioIndex, setAudioIndex] = useState(0)
  const [playerSliderValue, setPlayerSliderValue] = useState(0)
  const [volumeSliderValue, setVolumeSliderValue] = useState(props.volume ?? 0.5)
  const [currentTime, setCurrentTime] = useState(0)
  const [durationTime, setDurationTime] = useState(0)
  const [playing, setPlaying] = useState(false)
  const [playMode, setPlayMode] = useState<PlayModeType>(props.playMode ?? 'order')
  const [error, setError] = useState(true)
  const [firstPlay, setFirstPlay] = useState(true)
  const [showLyric, setShowLyric] = useState(false)
  const [close, setClose] = useState(false)

  const [panelMode, setPanelMode] = useState(props.panelMode)
  const defaultAudioPic = props.defaultAudioPic
  const playerIcons = { ...props.playerIcons }
  const zIndex = props.zIndex ?? 1000
  const iconColor = props.iconColor ?? colorText
  const fontColor = props.fontColor ?? colorText
  const miniStyleLeft = props.miniStyle?.left
  const miniStyleRight = props.miniStyle?.right
  const miniStyleTop = props.miniStyle?.top
  const miniStyleBottom = props.miniStyle?.bottom
  const playerTheme = props.playerTheme
  useEffect(() => {
    setAudio(audioList?.length > 0 ? audioList[0] : defalutAudio)
  }, [audioList])

  useEffect(() => {
    if (audioRef.current !== null) {
      audioRef.current.load()
    }
  }, [audioIndex])

  useEffect(() => {
    if (audioRef.current !== null) {
      audioRef.current.volume = volumeSliderValue
    }
  }, [volumeSliderValue])

  const initControlPanel = (): ReactNode => {
    if (panelMode === 'bottom') {
      return <BottomControlPanel {...controlPanelProps} />
    } else if (panelMode === 'mini') {
      return <MiniControlPanel {...controlPanelProps} />
    }
  }
  const onChangePlayerSlider = (value: number): void => {
    console.log('onChangePlayerSlider: ', value)
    setPlayerSliderValue(value)
    changing = true
  }

  const onChangeCompletePlayerSlider = (value: number): void => {
    console.log('onChangeCompletePlayerSlider: ', value)

    changing = false
    setCurrentTime(value * durationTime)
    if (audioRef.current !== null) {
      audioRef.current.currentTime = value * durationTime
    }
  }

  const onChangeVolumeSlider = (value: number): void => {
    console.log('onChangeVolumeSlider: ', value)
    setVolumeSliderValue(value)
  }

  const onPlay = (): void => {
    console.log('onPlay')
    setFirstPlay(false)
    if (audioRef.current !== null && !error) {
      audioRef.current.volume = 0
      audioRef.current.play().catch((e) => { console.error(e) })
    }
    clearInterval(fadeInOutInterval)
    fadeInOutInterval = setInterval(() => {
      if (audioRef.current !== null) {
        const volume = Number((audioRef.current.volume + volumeSliderValue / 10).toFixed(3))
        if (volume < volumeSliderValue) {
          audioRef.current.volume = volume
        } else {
          clearInterval(fadeInOutInterval)
        }
      }
    }, 50)
  }

  const onPause = (): void => {
    console.log('onPause')
    setPlaying(false)
    clearInterval(fadeInOutInterval)
    fadeInOutInterval = setInterval(() => {
      if (audioRef.current !== null) {
        const volume = Number((audioRef.current.volume - volumeSliderValue / 10).toFixed(3))
        if (volume > 0) {
          audioRef.current.volume = volume
        } else {
          clearInterval(fadeInOutInterval)
          if (audioRef.current !== null) {
            audioRef.current.pause()
          }
        }
      }
    }, 50)
  }

  const onPlayPrev = (): void => {
    let index

    if (playMode === 'random') {
      do {
        index = Math.random() * audioList.length | 0
      } while (index === audioIndex)
    } else {
      index = audioIndex === 0 ? audioList.length - 1 : audioIndex - 1
    }

    onPlayAudio(index)
  }

  const onPlayNext = (): void => {
    let index

    if (playMode === 'random') {
      do {
        index = Math.random() * audioList.length | 0
      } while (index === audioIndex)
    } else {
      index = audioIndex === audioList.length - 1 ? 0 : audioIndex + 1
    }

    onPlayAudio(index)
  }

  const onPlayAudio = (index: number): void => {
    if (index === audioIndex) {
      if (audioRef.current !== null) {
        audioRef.current.load()
      }
    } else {
      setAudioIndex(index)
      setAudio(audioList[index])
      onPlay()
    }
  }

  const onChangePlayMode = (): void => {
    let nextPlayMode: PlayModeType
    if (playMode === 'order') {
      nextPlayMode = 'single'
    } else if (playMode === 'single') {
      nextPlayMode = 'random'
    } else {
      nextPlayMode = 'order'
    }
    setPlayMode(nextPlayMode)
    if (typeof props.onChangePlayMode === 'function') {
      props.onChangePlayMode(nextPlayMode)
    }
  }

  const onDownLoad = (index: number, e: React.MouseEvent<HTMLDivElement, MouseEvent>): void => {
    !error && downloadFile(audioList[index].src, audioList[index].name)
    e.stopPropagation()
  }

  const onShowLyric = (): void => {
    setShowLyric(!showLyric)
    if (typeof props.onLyricOpenChange === 'function' && !showLyric) {
      props.onLyricOpenChange(!showLyric)
    }
  }

  const onClose = (): void => {
    setClose(true)
  }

  const onClickVolume = (): void => {
    console.log('onClickVolume')
    if (volumeSliderValue > 0) {
      setVolumeSliderValue(0)
    } else {
      setVolumeSliderValue(1)
    }
  }

  const onClearAudioList = (): void => {
    setAudioList([])
  }

  const onRemoveAudioIndex = (index: number, e: React.MouseEvent<HTMLDivElement, MouseEvent>): void => {
    setAudioList(audioList.filter((d, i) => index !== i))
    e.stopPropagation()
  }

  const onChangePanelMode = (playMode: PanelModeType): void => {
    setPanelMode(playMode)
  }

  const onChangePlayTheme = (): void => {
    props.changePlayerTheme()
  }

  const controlPanelProps: ControlPanelProps = {
    error,
    audio,
    audioList,
    audioIndex,
    playerSliderValue,
    volumeSliderValue,
    currentTime: formatTime(currentTime),
    durationTime: formatTime(durationTime),
    playing,
    playMode,
    showLyric,
    defaultAudioPic,
    playerIcons,
    iconColor,
    fontColor,
    miniStyleLeft,
    miniStyleRight,
    miniStyleTop,
    miniStyleBottom,
    playerTheme,
    onChangePlayerSlider,
    onChangeCompletePlayerSlider,
    onChangeVolumeSlider,
    onPlay,
    onPause,
    onPlayPrev,
    onPlayNext,
    onChangePlayMode,
    onDownLoad,
    onShowLyric,
    onClose,
    onClickVolume,
    onPlayAudio,
    onClearAudioList,
    onRemoveAudioIndex,
    onChangePanelMode,
    onChangePlayTheme
  }

  return (
    <div className="react-music-player" style={{ zIndex, color: fontColor }}>
      {!close && <div>
        <audio
          ref={audioRef}
          className="music-player-audio"
          src={audio.src}
          loop={playMode === 'single'}
          onAbort={() => {
            console.log('onAbort 当发生中止事件时运行脚本')
          }}
          onCanPlay={() => {
            console.log('onCanPlay 当媒介能够开始播放但可能因缓冲而需要停止时运行脚本')
            setError(false)
            if (audioRef.current !== null && !firstPlay) {
              audioRef.current.play().catch(e => { console.error(e) })
            }
          }}
          onCanPlayThrough={() => {
            console.log('onCanPlayThrough 当媒介能够无需因缓冲而停止即可播放至结尾时运行脚本')
          }}
          onDurationChange={() => {
            console.log('onDurationChange 当媒介长度改变时运行脚本')
            if (audioRef.current !== null) {
              setDurationTime(audioRef.current.duration)
            }
          }}
          onEmptied={() => {
            console.log('onEmptied 当媒介资源元素突然为空时（网络错误、加载错误等）运行脚本')
            setError(true)
          }}
          onEnded={() => {
            console.log('onEnded 当媒介已抵达结尾时运行脚本')
            if (playMode !== 'single') {
              onPlayNext()
            }
          }}
          onError={() => {
            console.log('onError 当在元素加载期间发生错误时运行脚本')
            setError(true)
          }}
          onLoadedData={() => {
            if (typeof props.onAudioChange === 'function') {
              props.onAudioChange(audio)
            }
            console.log('onLoadedData 当加载媒介数据时运行脚本')
          }}
          onLoadedMetadata={() => {
            console.log('onLoadedMetadata 当媒介元素的持续时间以及其他媒介数据已加载时运行脚本')
          }}
          onLoadStart={() => {
            setCurrentTime(0)
            setDurationTime(0)
            console.log('onLoadStart 当浏览器开始加载媒介数据时运行脚本')
          }}
          onPause={() => {
            console.log('onPause 当媒介数据暂停时运行脚本')
            if (typeof props.onAudioPause === 'function') {
              props.onAudioPause(audio)
            }
          }}
          onPlay={() => {
            console.log('onPlay 当媒介数据将要开始播放时运行脚本')
            if (typeof props.onAudioPlay === 'function') {
              props.onAudioPlay(audio)
            }
          }}
          onPlaying={() => {
            console.log('onPlaying 当媒介数据已开始播放时运行脚本')
            setPlaying(true)
          }}
          onProgress={() => {
            console.log('onProgress 当浏览器正在取媒介数据时运行脚本')
          }}
          onRateChange={() => {
            console.log('onRateChange 当媒介数据的播放速率改变时运行脚本')
          }}
          onSeeked={() => {
            console.log('onSeeked 当媒介元素的定位属性 [1] 不再为真且定位已结束时运行脚本')
          }}
          onSeeking={() => {
            console.log('onSeeking 当媒介元素的定位属性为真且定位已开始时运行脚本')
          }}
          onStalled={() => {
            console.log('onStalled 当取回媒介数据过程中（延迟）存在错误时运行脚本')
          }}
          onSuspend={() => {
            console.log('onSuspend 当浏览器已在取媒介数据但在取回整个媒介文件之前停止时运行脚本')
          }}
          onTimeUpdate={() => {
            let count = 10
            const timer = setInterval(function () {
              if (audioRef.current !== null && !changing) {
                setCurrentTime(audioRef.current.currentTime)
                setPlayerSliderValue(audioRef.current.currentTime / audioRef.current.duration)
                if (typeof props.onCurrentTimeChange === 'function') {
                  props.onCurrentTimeChange(audioRef.current.currentTime)
                }
              } if (count === 0) {
                clearInterval(timer)
              } else {
                count--
              }
            }, 25)
          }}
          onVolumeChange={() => {
            console.log('onVolumeChange 当媒介改变音量亦或当音量被设置为静音时运行脚本')
            if (typeof props.onVolumeChange === 'function') {
              props.onVolumeChange(volumeSliderValue)
            }
          }}
          onWaiting={() => {
            console.log('onWaiting 当媒介已停止播放但打算继续播放时运行脚本')
          }}
        />
        <ConfigProvider
          theme={{
            components: {
              Slider: {
                handleSize: 8,
                handleSizeHover: 8,
                handleLineWidthHover: 2,
                railSize: 4
              }
            },
            token: {
              colorText: fontColor,
              colorPrimary: iconColor
            }
          }}
        >
          {initControlPanel()}
        </ConfigProvider>

        <Lyric emptyLyricDescription={props.emptyLyricDescription} lyric={audio.lyric} tLyric={audio.tLyric} currentTime={currentTime} playMode="desktop" show={showLyric} />
        {/* <Lyric lyric={audio.lyric} currentTime={currentTime} playMode="roll" show={showLyric} /> */}
      </div>}
    </div>

  )
}
export default ReactMusicPlayer
